package com.acceptable.qucun.generic.aspect;

import com.acceptable.qucun.generic.exception.BaseException;
import com.acceptable.qucun.generic.util.CodeUtil;
import com.acceptable.qucun.generic.util.result.error.BaseErrorResult;
import com.acceptable.qucun.generic.util.result.error.GenericErrorResult;
import com.acceptable.qucun.generic.util.result.ResultUtil;
import com.acceptable.qucun.generic.util.result.success.BaseSuccessResult;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.locks.Lock;

@Component
@Aspect
public class SecretAspect {
    @Autowired private Lock lock;

    @Pointcut("execution(!void && !String com.acceptable.qucun.*.controller.*Controller.*(..))")
    public void secretPoint(){}

    @Pointcut("execution(String com.acceptable.qucun.*.controller.*Controller.*(..))")
    public void returnString(){}

    @Around("returnString()")
    public String returnString(ProceedingJoinPoint joinPoint){
        lock.lock();
        try {
            String code = (String) joinPoint.proceed();
            return ResultUtil.success(ResultUtil.getSuccessResultFromAll(code));
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            BaseErrorResult errorResult = ResultUtil.getErrorResultFromAll(throwable.getMessage());
            return ResultUtil.error(errorResult);
        } finally {
            lock.unlock();
        }
    }

    /**
     *  controller的请求处理方法返回值 除功能响应码以外的数据进行Base64加密
     */
    @Around(value = "secretPoint()")
    public Object secretReturnValue(ProceedingJoinPoint joinPoint) {
        Object res = null;
        lock.lock();
        try {
            res = joinPoint.proceed();
            if(res.getClass().getSimpleName().contains("String")){
                res = ResultUtil.success(ResultUtil.getSuccessResultFromAll((String) res), null, null);
            } else if(res.getClass().getSimpleName().contains("Map")){
                Map<String, Object> dataMap = (Map<String, Object>) res;
                // 获取除响应码以外的所有controller返回的 数据
                String code = (String) dataMap.get("code");
                BaseSuccessResult result = ResultUtil.getSuccessResultFromAll(code);
                String msg = result == null ? "": result.getMsg();
                // 只保留除响应码以外的数据
                {
                    dataMap.remove("code");
                    if (dataMap.containsKey("msg")){
                        msg = (String) dataMap.get("msg");
                        dataMap.remove("msg");
                    }
                }

                // 对保留的数据进行集体包装加密
                {
                    Map<String, String> codeMap = Collections.emptyMap();
                    if(dataMap.size() > 0)
                        codeMap = CodeUtil.base64Encode(dataMap);

                    // 删除除响应码以外的数据 响应码以及相关信息之前删除过了
                    dataMap.clear();

                    // 放入加密后的数据
                    dataMap.put("data", codeMap);
                }

                // 放入响应码等相关信息
                {
                    dataMap.put("code", code);
                    dataMap.put("msg", msg);
                }
            }
        } catch (BaseException e){
            e.printStackTrace();
            String expr = joinPoint.toString();
            String valueType = expr.substring(expr.indexOf("(") + 1, expr.indexOf(" "));
            BaseErrorResult errorResult = ResultUtil.getErrorResultFromAll(e.getMessage());
            if (!valueType.contains("Map")){
                return ResultUtil.error(errorResult);
            }
            Map<String, Object> errorMap = new HashMap<>();
            errorMap.clear();
            errorMap.put("code", errorResult.getCode());
            errorMap.put("msg", errorResult.getMsg());
            return errorMap;

        } catch (IllegalArgumentException e) {
            e.printStackTrace();
            return ResultUtil.error(GenericErrorResult.DATA_CODE_ERROR);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        } finally {
            lock.unlock();
        }
        return res;
    }

}
